package com.xhai.admin.service;

import com.xhai.common.cache.RedisCache;
import com.xhai.common.constant.ConfigConstants;
import com.xhai.common.constant.RedisConstants;
import com.xhai.common.constant.UserConstants;
import com.xhai.common.domain.login.LoginSucInfo;
import com.xhai.common.domain.login.LoginUser;
import com.xhai.common.domain.vo.UserInfo;
import com.xhai.common.exception.ServiceException;
import com.xhai.common.exception.captcha.CaptchaErrorException;
import com.xhai.common.exception.captcha.CaptchaInvalidException;
import com.xhai.common.exception.user.LoginBlackIPListException;
import com.xhai.common.exception.user.UserNotExistsException;
import com.xhai.common.exception.user.UserPasswordNotMatchException;
import com.xhai.common.exception.user.UserUsernameNotMatchException;
import com.xhai.common.utils.i18n.MessageUtils;
import com.xhai.common.utils.classes.StringUtils;
import com.xhai.common.utils.ip.IpUtils;
import com.xhai.security.context.AuthenticationContextHolder;
import com.xhai.service.SysConfigService;
import jakarta.annotation.Resource;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.stereotype.Service;

/**
 * @author xhai
 * @description 登录服务
 * @date 2025/5/29
 */
@Service
public class LoginService {

    @Resource
    AuthenticationManager authenticationManager;

    @Resource
    private SysConfigService sysConfigService;

    @Resource
    private RedisCache redisCache;

    @Resource
    private TokenService tokenService;

    /**
     * 登录校验，成功返回token，失败报错
     *
     * @param username    用户名
     * @param password    密码
     * @param captchaCode 验证码
     * @param captchaUuid 验证码唯一标识uuid
     * @return
     */
    public LoginSucInfo login(String username, String password, String captchaCode, String captchaUuid) {
        // 验证码校验
        validateCaptcha(username, captchaCode, captchaUuid);
        // 登录前置校验
        loginPreCheck(username, password);
        // 用户验证
        Authentication authentication = null;
        try {
            UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(username, password);
            // 用于在校验密码时获取密码
            AuthenticationContextHolder.setContext(authenticationToken);
            // 该方法会去调用UserDetailsServiceImpl.loadUserByUsername
            authentication = authenticationManager.authenticate(authenticationToken);
        } catch (Exception e) {
            if (e instanceof BadCredentialsException) {
//                AsyncManager.me().execute(AsyncFactory.recordLogininfor(username, Constants.LOGIN_FAIL, MessageUtils.message("user.password.not.match")));
                throw new UserPasswordNotMatchException();
            } else {
//                AsyncManager.me().execute(AsyncFactory.recordLogininfor(username, Constants.LOGIN_FAIL, e.getMessage()));
                throw new ServiceException(e.getMessage());
            }
        } finally {
            AuthenticationContextHolder.clearContext();
        }
//        AsyncManager.me().execute(AsyncFactory.recordLogininfor(username, Constants.LOGIN_SUCCESS, MessageUtils.message("user.login.success")));
        LoginUser loginUser = (LoginUser) authentication.getPrincipal();
        // 生成token
        String token = tokenService.createToken(loginUser);
        return createLoginSucInfo(loginUser, token);
    }

    /**
     * 生成登陆成功后返回信息
     *
     * @param loginUser
     * @param token
     * @return
     */
    private LoginSucInfo createLoginSucInfo(LoginUser loginUser, String token) {
        LoginSucInfo loginSucInfo = new LoginSucInfo();

        UserInfo userInfo = new UserInfo();
        userInfo.setUsername(loginUser.getUsername());

        loginSucInfo.setUser(userInfo);
        loginSucInfo.setToken(token);
        return loginSucInfo;
    }

    /**
     * 校验验证码
     *
     * @param username    用户名
     * @param captchaCode 验证码
     * @param captchaUuid 验证码唯一标识uuid
     */
    private void validateCaptcha(String username, String captchaCode, String captchaUuid) {
        // 判断验证码配置是否开启
        boolean captchaCheckEnabled = sysConfigService.selectCaptchaCheckEnabled();

        if (captchaCheckEnabled) {
            // 获取验证码校验方式
            String captchaCheckMode = sysConfigService.selectCaptchaCheckMode();

            // 根据不同验证码校验方式校验
            switch (captchaCheckMode) {
                case ConfigConstants.SYS_CAPTCHA_CHECK_MODE_PICTURE: {
                    String captchaKey = RedisConstants.REDIS_KEY_PREFIX_CAPTCHA + captchaUuid;
                    String redisCaptchaCode = redisCache.getCacheObject(captchaKey);
                    if (StringUtils.isEmpty(redisCaptchaCode)) {
//                        AsyncManager.me().execute(AsyncFactory.recordLogininfor(username, Constants.LOGIN_FAIL, MessageUtils.message("captcha.invalid")));
                        throw new CaptchaInvalidException();
                    }
                    if (!StringUtils.equalsIgnoreCase(captchaCode, redisCaptchaCode)) {
//                        AsyncManager.me().execute(AsyncFactory.recordLogininfor(username, Constants.LOGIN_FAIL, MessageUtils.message("captcha.error")));
                        throw new CaptchaErrorException();
                    }
                    redisCache.deleteObject(captchaKey);
                }
            }
        }
    }

    /**
     * 登录前置校验
     *
     * @param username 用户名
     * @param password 密码
     */
    private void loginPreCheck(String username, String password) {
        // 用户名或密码为空 错误
        if (StringUtils.isEmpty(username) || StringUtils.isEmpty(password)) {
//            AsyncManager.me().execute(AsyncFactory.recordLogininfor(username, Constants.LOGIN_FAIL, MessageUtils.message("user.info.null")));
            throw new UserNotExistsException();
        }
        // 密码如果不在指定范围内 错误
        if (password.length() < UserConstants.PASSWORD_MIN_LENGTH
                || password.length() > UserConstants.PASSWORD_MAX_LENGTH) {
//            AsyncManager.me().execute(AsyncFactory.recordLogininfor(username, Constants.LOGIN_FAIL, MessageUtils.message("user.password.not.match")));
            throw new UserPasswordNotMatchException();
        }
        // 用户名不在指定范围内 错误
        if (username.length() < UserConstants.USERNAME_MIN_LENGTH
                || username.length() > UserConstants.USERNAME_MAX_LENGTH) {
//            AsyncManager.me().execute(AsyncFactory.recordLogininfor(username, Constants.LOGIN_FAIL, MessageUtils.message("user.username.not.match")));
            throw new UserUsernameNotMatchException();
        }
        // IP黑名单校验
        String loginBlackIPListStr = sysConfigService.selectLoginBlackIPList();
        if (IpUtils.isMatchedIp(loginBlackIPListStr, IpUtils.getServletIpAddr())) {
//            AsyncManager.me().execute(AsyncFactory.recordLogininfor(username, Constants.LOGIN_FAIL, MessageUtils.message("login.black.ip.list")));
            throw new LoginBlackIPListException();
        }
    }
}
